package drds.global_transaction.transaction_coordinator.transaction_session;

import drds.global_transaction.api.api.BranchTransactionStatus;
import drds.global_transaction.api.api.GlobalTransactionStatus;
import drds.global_transaction.api.exception.GlobalTransactionException;
import drds.global_transaction.transaction_coordinator.store.OperationType;
import drds.global_transaction.transaction_coordinator.store.TransactionStoreManager;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public abstract class AbstractTransactionSessionManager implements TransactionSessionManager, TransactionSessionLifecycleListener
{

	protected Map<Long, GlobalTransactionSession> globalTransactionIdToGlobalTransactionSessionMap = new ConcurrentHashMap<>();

	protected TransactionStoreManager transactionStoreManager;

	protected String name;

	public AbstractTransactionSessionManager(String name)
	{
		this.name = name;
	}

	@Override
	public void addBranchTransactionSession(GlobalTransactionSession globalTransactionSession, BranchTransactionSession branchTransactionSession) throws GlobalTransactionException
	{
		if (log.isDebugEnabled())
		{
			log.debug("MANAGER[" + name + "] SESSION[" + branchTransactionSession + "] " + OperationType.add_branch_transaction);
		}
		transactionStoreManager.saveOperation(branchTransactionSession, OperationType.add_branch_transaction);
	}

	@Override
	public void addGlobalTransactionSession(GlobalTransactionSession globalTransactionSession) throws GlobalTransactionException
	{
		if (log.isDebugEnabled())
		{
			log.debug("MANAGER[" + name + "] SESSION[" + globalTransactionSession + "] " + OperationType.add_global_transaction);
		}
		transactionStoreManager.saveOperation(globalTransactionSession, OperationType.add_global_transaction);
		globalTransactionIdToGlobalTransactionSessionMap.put(globalTransactionSession.getGlobalTransactionId(), globalTransactionSession);

	}

	@Override
	public GlobalTransactionSession getGlobalTransactionSession(Long globalTransactionId) throws GlobalTransactionException
	{
		return globalTransactionIdToGlobalTransactionSessionMap.get(globalTransactionId);
	}

	@Override
	public Collection<GlobalTransactionSession> getGlobalTransactionSessionList()
	{
		return globalTransactionIdToGlobalTransactionSessionMap.values();
	}

	@Override
	public List<GlobalTransactionSession> getGlobalTransactionSessionList(TransactionSessionCondition transactionSessionCondition)
	{
		List<GlobalTransactionSession> found = new ArrayList<>();
		for (GlobalTransactionSession globalTransactionSession : globalTransactionIdToGlobalTransactionSessionMap.values())
		{
			if (globalTransactionSession.getGlobalTransactionStatus() == transactionSessionCondition.getGlobalTransactionStatus())
			{
				if (System.currentTimeMillis() - globalTransactionSession.getBeginDataTimeLong() > transactionSessionCondition.getOverTimeAliveMills())
				{
					found.add(globalTransactionSession);
				}
			}
		}
		return found;
	}

	@Override
	public void onAddBranchTransactionSession(GlobalTransactionSession globalTransactionSession, BranchTransactionSession branchTransactionSession) throws GlobalTransactionException
	{
		addBranchTransactionSession(globalTransactionSession, branchTransactionSession);
	}

	@Override
	public void onBeginGlobalTransactionSession(GlobalTransactionSession globalTransactionSession) throws GlobalTransactionException
	{
		addGlobalTransactionSession(globalTransactionSession);
	}

	@Override
	public void onBranchTransactionStatusChange(GlobalTransactionSession globalTransactionSession, BranchTransactionSession branchTransactionSession, BranchTransactionStatus status) throws GlobalTransactionException
	{
		updateBranchTransactionSessionStatus(branchTransactionSession, status);
	}

	@Override
	public void onCloseGlobalTransactionSession(GlobalTransactionSession globalTransactionSession) throws GlobalTransactionException
	{
		globalTransactionSession.setActive(false);

	}

	@Override
	public void onEndGlobalTransactionSession(GlobalTransactionSession globalTransactionSession) throws GlobalTransactionException
	{
		removeGlobalTransactionSession(globalTransactionSession);

	}

	@Override
	public void onGlobalTransactionStatusChange(GlobalTransactionSession globalTransactionSession, GlobalTransactionStatus status) throws GlobalTransactionException
	{
		updateGlobalTransactionSessionStatus(globalTransactionSession, status);
	}

	@Override
	public void onRemoveBranchTransactionSession(GlobalTransactionSession globalTransactionSession, BranchTransactionSession branchTransactionSession) throws GlobalTransactionException
	{
		removeBranchTransactionSession(globalTransactionSession, branchTransactionSession);
	}

	@Override
	public void removeBranchTransactionSession(GlobalTransactionSession globalTransactionSession, BranchTransactionSession branchTransactionSession) throws GlobalTransactionException
	{
		if (log.isDebugEnabled())
		{
			log.debug("MANAGER[" + name + "] SESSION[" + branchTransactionSession + "] " + OperationType.add_global_transaction);
		}
		transactionStoreManager.saveOperation(branchTransactionSession, OperationType.remove_branch_transaction);

	}

	@Override
	public void removeGlobalTransactionSession(GlobalTransactionSession globalTransactionSession) throws GlobalTransactionException
	{
		if (log.isDebugEnabled())
		{
			log.debug("MANAGER[" + name + "] SESSION[" + globalTransactionSession + "] " + OperationType.remove_global_transaction);
		}
		transactionStoreManager.saveOperation(globalTransactionSession, OperationType.remove_global_transaction);
		globalTransactionIdToGlobalTransactionSessionMap.remove(globalTransactionSession.getGlobalTransactionId());

	}

	@Override
	public void updateBranchTransactionSessionStatus(BranchTransactionSession branchTransactionSession, BranchTransactionStatus branchTransactionStatus) throws GlobalTransactionException
	{
		if (log.isDebugEnabled())
		{
			log.debug("MANAGER[" + name + "] SESSION[" + branchTransactionSession + "] " + OperationType.add_global_transaction);
		}
		transactionStoreManager.saveOperation(branchTransactionSession, OperationType.update_branch_transaction);

	}

	@Override
	public void updateGlobalTransactionSessionStatus(GlobalTransactionSession globalTransactionSession, GlobalTransactionStatus globalTransactionStatus) throws GlobalTransactionException
	{
		if (log.isDebugEnabled())
		{
			log.debug("MANAGER[" + name + "] SESSION[" + globalTransactionSession + "] " + OperationType.update_global_transaction);
		}
		transactionStoreManager.saveOperation(globalTransactionSession, OperationType.update_global_transaction);
	}
}
